﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using DomainDriver.DomainModeling.Constraints;
using DomainDriver.DomainModeling.DataProviders;
using DomainDriver.DomainModeling.DomainObjects;
using DomainDriver.DomainModeling.Events;
using DomainDriver.DomainModeling.Repositories;
using DomainDriver.DomainModeling.TransactionScripts;

namespace DomainDriver.DomainModeling.DomainModels
{
    public interface IDomainModel
    {
        event DataSourceConfigurationDelegate ConfigureDataSource;
        event ConstraintCreationDelegate CreateConstraints;

        bool BuildModelWithConstraints { get; }
        DataSourcePersistenceType PersistenceType { get; }
        IDataProvider DataProvider { get; }
        IDictionary<DataSourcePersistenceType, Type> DataSourceTypesForPersistenceTypes { get; }
        IList<IConstraint> Constraints { get; }

        // Initialization Methods
        void RegisterDataSource<DATASOURCE>(DataSourcePersistenceType persistenceType, Func<Type, Type, Type, IDataProvider, Expression, IDomainModel, object> repositoryConstructionMethod)
            where DATASOURCE : new();
        void RegisterDataSource(DataSourcePersistenceType persistenceType, Type dataSourceType, Func<Type, Type, Type, IDataProvider, Expression, IDomainModel, object> repositoryConstructionMethod);
        void RegisterDomainObjectRepository<KEY, KEYED_DOMAIN_OBJECT>()
            where KEYED_DOMAIN_OBJECT : IKeyedDomainObject<KEY, KEYED_DOMAIN_OBJECT>, new();
        void RegisterDomainObjectRepository<KEY, KEYED_DOMAIN_OBJECT>(Expression<Func<KEYED_DOMAIN_OBJECT>> constructionMethod)
            where KEYED_DOMAIN_OBJECT : IKeyedDomainObject<KEY, KEYED_DOMAIN_OBJECT>;
        void RegisterDomainObjectRepository<DOTNET_KEY, DB_KEY, KEYED_DOMAIN_OBJECT>()
            where KEYED_DOMAIN_OBJECT : IKeyedDomainObject<DOTNET_KEY, KEYED_DOMAIN_OBJECT>, new();
        void RegisterDomainObjectRepository<DOTNET_KEY, DB_KEY, KEYED_DOMAIN_OBJECT>(Expression<Func<KEYED_DOMAIN_OBJECT>> constructionMethod)
            where KEYED_DOMAIN_OBJECT : IKeyedDomainObject<DOTNET_KEY, KEYED_DOMAIN_OBJECT>;
        void RegisterDomainObjectRepository(Type dotNetKeyType, Type databaseKeyType, Type keyedDomainObjectType, Expression constructionMethod);
        void AddModelConstraint(IConstraint constraint);
        void Initialize();

        // Usage Methods
        DATASOURCE CreateDataSource<DATASOURCE>(DataSourcePersistenceType persistenceType);
        object CreateDataSource(DataSourcePersistenceType persistenceType);
        DATA_PROVIDER GetDataProvider<DATA_PROVIDER>()
            where DATA_PROVIDER : IDataProvider;
        IDataProvider GetDataProvider();
        bool HasConstraint<CONSTRAINT>()
            where CONSTRAINT : IConstraint;
        CONSTRAINT GetConstraint<CONSTRAINT>()
            where CONSTRAINT : IConstraint;
        bool HasRepository<KEY, KEYED_DOMAIN_OBJECT>()
            where KEYED_DOMAIN_OBJECT : IKeyedDomainObject<KEY, KEYED_DOMAIN_OBJECT>;
        IRepository<KEY, KEYED_DOMAIN_OBJECT> GetRepository<KEY, KEYED_DOMAIN_OBJECT>()
            where KEYED_DOMAIN_OBJECT : IKeyedDomainObject<KEY, KEYED_DOMAIN_OBJECT>;
        TRANSACTION_SCRIPT CreateTransactionScript<TRANSACTION_SCRIPT>()
            where TRANSACTION_SCRIPT : ITransactionScript, new();
    }
}